package chapter21;

public abstract class GenericMatrix<E extends Number> {
	
	//矩阵元素相加
	protected abstract E add(E o1, E o2);
	
	//矩阵元素相乘
	protected abstract E multiply(E o1, E o2);
	
	//设置矩阵为零
	protected abstract E zero();
	
	public E[][] addMatrix(E[][] matrix1, E[][] matrix2) {
		/*求矩阵之和*/
		
		//判断两个矩阵的行列数是否相同
		if ((matrix1.length != matrix2.length) || 
				(matrix1[0].length != matrix2[0].length)) {
			throw new RuntimeException(
					"The matrices do not have the same size");
		}
		
		E[][] result = (E[][]) new Number[matrix1.length][matrix1[0].length];
		
		//矩阵元素求和，并将求和后的元素给result
		for (int i = 0; i < result.length; i++) {
			for (int j = 0; j < result[i].length; j++) {
				result[i][j] = add(matrix1[i][j], matrix2[i][j]);
			}
		}
		
		return result;
	}
	
	public E[][] multiplyMatrix(E[][] matrix1, E[][] matrix2) {
		/*求矩阵之积*/
		
		if (matrix1[0].length != matrix2.length) {
			throw new RuntimeException("The matrices do not have compatible size");
		}
		
		E[][] result = (E[][]) new Number[matrix1.length][matrix2[0].length];
		
		for (int i = 0; i < matrix1.length; i++) {
			for (int j = 0; j < matrix1[i].length; j++) {
				result[i][j] = zero();
				
				for (int k = 0; k < matrix1[0].length; k++) {
					//matrix1的行数不变，列数在变，行数取值同result的行，即为i
					//matrix2的列数不变，行数在变，行数取值同result的列，即为j
					result[i][j] = add(result[i][j], multiply(matrix1[i][k], matrix2[k][j]));
				}
			}
		}
		
		return result;
	}
	
	public static void printResult (
			Number[][] m1, Number[][] m2, Number[][] m3, char op) {
		for (int i = 0; i < m1.length; i++) {
			for (int j = 0; j < m1[0].length; j++) 
				System.out.print("  " + m1[i][j]);
				
				if (i == m1.length / 2) 
					System.out.print("  " + op + "  ");
				else
					System.out.print("     ");
				
				for (int j = 0; j < m2.length; j++) 
					System.out.print("  " + m2[i][j]);
				
				if (i == m1.length / 2) 
					System.out.print("  =  ");
				else
					System.out.print("     ");
				
				for (int j = 0; j < m3.length; j++) 
					System.out.print(" " + m3[i][j]);
				
				System.out.println();
				
			
		}
	}

}
